001    /*
002     * Copyright 2004 Niclas Hedhman
003     * Copyright 2004-2006 Stephen J. McConnell
004     *
005     * Licensed  under the  Apache License,  Version 2.0  (the "License");
006     * you may not use  this file  except in  compliance with the License.
007     * You may obtain a copy of the License at
008     *
009     *   http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed  under the  License is distributed on an "AS IS" BASIS,
013     * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
014     * implied.
015     *
016     * See the License for the specific language governing permissions and
017     * limitations under the License.
018     */
019    
020    package net.dpml.transit.artifact;
021    
022    import java.io.InputStream;
023    import java.io.IOException;
024    import java.io.OutputStream;
025    import java.io.File;
026    import java.net.UnknownServiceException;
027    import java.net.URI;
028    import java.net.URL;
029    import java.net.URLConnection;
030    import java.net.URISyntaxException;
031    
032    import net.dpml.transit.Artifact;
033    import net.dpml.transit.Transit;
034    import net.dpml.transit.SecuredTransitContext;
035    import net.dpml.transit.CacheHandler;
036    
037    import net.dpml.lang.Part;
038    
039    import net.dpml.util.MimeTypeHandler;
040    
041    /**
042     * The connection handler for URLs based on the "artifact" protocol family.
043     * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
044     * @version 1.0.1
045     */
046    public class ArtifactURLConnection extends URLConnection
047    {
048        // ------------------------------------------------------------------------
049        // state
050        // ------------------------------------------------------------------------
051    
052       /**
053        * Transit context.
054        */
055        private final SecuredTransitContext m_context;
056    
057       /**
058        * Artifact.
059        */
060        private final Artifact m_artifact;
061    
062       /**
063        * Reference fragment.
064        */
065        private final String m_reference;
066    
067       /**
068        * The connected state.
069        */
070        private boolean m_connected;
071    
072        // ------------------------------------------------------------------------
073        // constructor
074        // ------------------------------------------------------------------------
075    
076        /**
077         * Creation of a new handler.
078         * @param url the url to establish a connection with
079         * @param context the transit context
080         * @exception NullPointerException if the url argument is null
081         * @exception IOException if the url argument is invalid
082          */
083        ArtifactURLConnection( URL url, SecuredTransitContext context )
084            throws NullPointerException, IOException
085        {
086            super( url );
087    
088            Transit.getInstance(); // make sure Transit is initialized
089    
090            m_context = context;
091            m_reference = getReference( url );
092    
093            String spec = getRealSpec( url, m_reference );
094            try
095            {
096                m_artifact = Artifact.createArtifact( spec );
097            }
098            catch( URISyntaxException e )
099            {
100                throw new IOException( e.toString() );
101            }
102        }
103    
104        // ------------------------------------------------------------------------
105        // URLConnection
106        // ------------------------------------------------------------------------
107    
108       /**
109        * Establish a connection.  The implementation will attempt to
110        * resolve the resource relative to the cache and associated hosts.
111        *
112        * @exception IOException is an error occurs while attempting to establish
113        *  the connection.
114        */
115        public void connect()
116            throws IOException
117        {
118            m_connected = true;
119        }
120    
121       /**
122        * Return an input stream to the resource.
123        * @return the input stream
124        * @exception IOException is an error occurs
125        */
126        public InputStream getInputStream()
127            throws IOException
128        {
129            connect();
130            CacheHandler cache = m_context.getCacheHandler();
131            if( null != m_reference )
132            {
133                return cache.getResource( m_artifact, m_reference );
134            }
135            else
136            {
137                return cache.getResource( m_artifact );
138            }
139        }
140    
141       /**
142        * Return an output stream to the resource.
143        * @return the output stream
144        * @exception IOException if any I/O problems occur.
145        */
146        public OutputStream getOutputStream()
147            throws IOException
148        {
149            CacheHandler cache = m_context.getCacheHandler();
150            return cache.createOutputStream( m_artifact );
151        }
152    
153       /**
154        * Reutrn the mimetype of the content.
155        * @return the content mimetype
156        */
157        public String getContentType()
158        {
159            String type = m_artifact.getType();
160            return MimeTypeHandler.getMimeType( type );
161        }
162    
163       /**
164        * Return the content for this artifact.
165        * @return the content object (possibly null)
166        * @exception IOException is an error occurs
167        */
168        public Object getContent()
169            throws IOException
170        {
171            Object content = getContent( new Class[0] );
172            if( content != null )
173            {
174                return content;
175            }
176            else
177            {
178                return super.getContent();
179            }
180        }
181    
182       /**
183        * Return the content for this artifact.
184        * @param classes a sequence of classes against which the
185        *   implementation will attempt to establish a known match
186        * @return the content object (possibly null)
187        * @exception IOException is an error occurs
188        */
189        public Object getContent( Class[] classes )
190            throws IOException
191        {
192        
193            //
194            // attempt to resolve this locally as we may be dealing
195            // with Depot references to the artifact File
196            //
197    
198            for( int i=0; i < classes.length; i++ )
199            {
200                Class c = classes[i];
201                if( c.equals( File.class ) )
202                {
203                    return m_context.getCacheHandler().getLocalFile( m_artifact );
204                }
205            }
206            
207            String type = m_artifact.getType();
208    
209            // 
210            // if the type is a plugin then handle this directly
211            //
212    
213            if( "part".equals( type ) )
214            { 
215                URI uri = m_artifact.toURI();
216                Part part = Part.load( uri );
217                return part.getContent( classes );
218            }
219            
220            //
221            // otherwise fallback on the default jvm content handling
222            //
223    
224            try
225            {
226                Object content = super.getContent( classes );
227                if( content != null )
228                {
229                    return content;
230                }
231            }
232            catch( UnknownServiceException use )
233            {
234                boolean ignoreThis = true;
235            }
236    
237            return null;
238        }
239        
240        // ------------------------------------------------------------------------
241        // implementation
242        // ------------------------------------------------------------------------
243    
244       /**
245        * Return a fragment referencing content within the resource referenced by
246        * the artifact.
247        * @param url the url
248        * @return the fragment or null if this is not a referential url
249        */
250        private String getReference( URL url )
251        {
252            String path = url.getPath();
253            int i = path.indexOf( '!' );
254            if( i < 0 )
255            {
256                return null;
257            }
258            else
259            {
260                return path.substring( i );
261            }
262        }
263    
264       /**
265        * Return the real specification of the supplied url.
266        * @param url the url to evaluate
267        * @param ref a reference fragment
268        * @return the artifact url spec withough the ref fragment
269        */
270        private String getRealSpec( URL url, String ref )
271        {
272            if( null != ref )
273            {
274                String spec = url.toString();
275                int j = spec.indexOf( ref );
276                if( j > 0 )
277                {
278                    String s = spec.substring( 0, j );
279                    String version = url.getUserInfo();
280                    if( null != version )
281                    {
282                        s = s + "#" + version;
283                    }
284                    return s;
285                }
286            }
287            return url.toString();
288        }
289    }